#include "user.h"
#define SELF_TASK_ID TASK_ID_USER
#define TASK_SIGNAL_NUM	(8)
#define UART_BUF_SIZE (512)
#define PARAM_MAX (8)
#define IO_MAX (32)
enum
{
	SIGNAL_START = SIGNAL_USER_DEFINE,
	SIGNAL_NEW_RX,
};

typedef struct
{
	Timer_t UserTimer;
	Timer_t RxTimer;
	CommandParamStruct Param[PARAM_MAX];
	uint16_t ADCBuf[12];
	Buffer_Struct RxBuf;
	uint8_t RxData[UART_BUF_SIZE];
	char TxData[UART_BUF_SIZE];
	char Ack[UART_BUF_SIZE/8];
	uint8_t IOIn[(IO_MAX - 1)/8+1];
	uint8_t IOOut[(IO_MAX - 1)/8+1];
}USER_CtrlStruct;


extern const GPIO_PinStruct InPin[];
extern const GPIO_PinStruct OutPin[];
extern const GPIO_PinStruct ADCPin[];
static USER_CtrlStruct UserCtrl;
static Signal_InfoStruct SignalBuf[TASK_SIGNAL_NUM];


static void User_PrintAddTail(char *Buf, int TxLen)
{
	uint16_t crc16;
	crc16 = CRC16Cal(Buf, TxLen, CRC16_START, CRC16_CCITT_GEN, 0);
	TxLen += sprintf(Buf + TxLen, "%04X\r\n", crc16);
	DBG_DirectOut(Buf, TxLen);
}

static int32_t User_PrintState(uint8_t *Data, uint32_t Len)
{
	int len;
	PV_Union PIn,POut;
	len = sprintf(UserCtrl.TxData, "$INFO,TAMP,%u,TYPE,fixture,MCU,%u.%u.%u*",
			(uint32_t)(Timer_GetUsecFromPoweron()/1000000), MAIN_VERSION, SUB_VERSION, BUILD_VERSION);
	User_PrintAddTail(UserCtrl.TxData, len);
	len = sprintf(UserCtrl.TxData, "$ID,SN,%08x%08x%08x*", LL_GetUID_Word0(), LL_GetUID_Word1(),
			LL_GetUID_Word2());
	User_PrintAddTail(UserCtrl.TxData, len);
	memcpy(PIn.u8, UserCtrl.IOIn, 4);
	memcpy(POut.u8, UserCtrl.IOOut, 4);
	len = sprintf(UserCtrl.TxData, "$HW,DIN0,%08x,DOUT0,%08x*", PIn.u32, POut.u32);
	User_PrintAddTail(UserCtrl.TxData, len);
	return ERROR_NONE;
}

static int32_t User_SetOut(uint8_t *Data, uint32_t Len)
{
	PV_Union POut;
	if (Len != 4)
	{
		return ERROR_PARAM_INVALID;
	}
	memcpy(POut.u8, Data, 4);
	return ERROR_NONE;
}

static void User_Error(int32_t ErrorCode)
{
	int len;
	len = sprintf(UserCtrl.Ack, "$ERR,CODE,%d*", ErrorCode);
	User_PrintAddTail(UserCtrl.Ack, len);
}


const MyDataCBExFun_t CmdDeal[] =
{
	User_PrintState,
	User_SetOut,
};

static void User_TimeoutCB(PV_Union pData)
{
	DBG_INFO("%u", NST1001_Read());
}

static void User_UartRxTimeoutCB(PV_Union pData)
{
	Task_SendOnlySignal(SELF_TASK_ID, SELF_TASK_ID, SIGNAL_NEW_RX);
}

static void User_UartCB(PV_Union pData)
{
	switch (pData.u32)
	{
	case UART_RX_IRQ:
		UserCtrl.RxBuf.Data[UserCtrl.RxBuf.Pos] = Uart_Rx(DBG_UART_ID);
		UserCtrl.RxBuf.Pos++;
		if (UserCtrl.RxBuf.Pos >= UserCtrl.RxBuf.MaxLen)
		{
			DBG_INFO("get data %dbyte", UserCtrl.RxBuf.Pos);
			UserCtrl.RxBuf.Pos = 0;
			Timer_Switch(&UserCtrl.RxTimer, 0);
		}
		else
		{
			Timer_Start(&UserCtrl.RxTimer, 0, 2000, 0);
		}
		break;
	case UART_TX_DONE_IRQ:
	case UART_TX_ERROR_IRQ:
		break;
	}
}

static void User_Timeout(Signal_InfoStruct *Signal)
{
	;
}

static void User_RxNewCmd(Signal_InfoStruct *Signal)
{
	Buffer_Struct Buf;
	int TxLen;
	uint32_t SN, Command;
	int32_t Res;
	uint16_t crc16, crc6_check;
	uint8_t Num;
	UserCtrl.RxData[UserCtrl.RxBuf.Pos] = 0;
	if (UserCtrl.RxBuf.Data[0] == '$' && UserCtrl.RxBuf.Data[UserCtrl.RxBuf.Pos - 5] == '*')
	{
		crc6_check = CRC16Cal(UserCtrl.RxBuf.Data, UserCtrl.RxBuf.Pos - 4, CRC16_START, CRC16_CCITT_GEN, 0);
		crc16 = StrToUint(&UserCtrl.RxBuf.Data[UserCtrl.RxBuf.Pos - 4]);
		if (crc16 != crc6_check)
		{
			DBG_INFO("0x%04x,0x%04x", crc16, crc6_check);
			User_Error(ERROR_CHECK_FAIL);
			goto ERROR_QUIT;
		}
		UserCtrl.RxBuf.Data[UserCtrl.RxBuf.Pos - 5] = ';';
		Buf.Data = &UserCtrl.RxBuf.Data[1];
		Buf.MaxLen = UserCtrl.RxBuf.Pos - 5;
		Buf.Pos = 0;
		memset(UserCtrl.Param, 0, sizeof(UserCtrl.Param));
		if (ERROR_NONE == ParseParam(&Buf, UserCtrl.Param, PARAM_MAX, &Num) && (7 == Num) )
		{
			if (memcmp(UserCtrl.Param[0].Value, "CTRL", UserCtrl.Param[0].Length)
					|| memcmp(UserCtrl.Param[1].Value, "SN", UserCtrl.Param[1].Length)
					|| memcmp(UserCtrl.Param[3].Value, "CMD", UserCtrl.Param[3].Length)
					|| memcmp(UserCtrl.Param[5].Value, "PARAM", UserCtrl.Param[5].Length))
			{
				User_Error(ERROR_PARAM_INVALID);
				goto ERROR_QUIT;
			}
			if (ParseGetU32FromParam(&UserCtrl.Param[2], &SN, 0, 0xffffffff, 0))
			{
				User_Error(ERROR_PARAM_INVALID);
				goto ERROR_QUIT;
			}
			if (ParseGetU32FromParam(&UserCtrl.Param[4], &Command, 0, sizeof(CmdDeal)/sizeof(MyDataCBFun_t), 0))
			{
				User_Error(ERROR_PARAM_INVALID);
				goto ERROR_QUIT;
			}
			UserCtrl.Param[6].Length = AsciiToHex(UserCtrl.Param[6].Value, UserCtrl.Param[6].Length, UserCtrl.Param[6].Value);
			DBG_INFO("%08x", CmdDeal[Command]);
			Res = CmdDeal[Command](UserCtrl.Param[6].Value, UserCtrl.Param[6].Length);
			TxLen = sprintf(UserCtrl.Ack, "$ACK,SN,%u,RES,%d*", SN, Res);
			User_PrintAddTail(UserCtrl.Ack, TxLen);
		}
		else
		{
			User_Error(ERROR_PARAM_INVALID);
			goto ERROR_QUIT;
		}
	}
ERROR_QUIT:
	UserCtrl.RxBuf.Pos = 0;
}

static const Signal_AnalyzeStruct SignalAnalyze[] =
{
		{SIGNAL_TASK_TIMEOUT, User_Timeout},
		{SIGNAL_NEW_RX, User_RxNewCmd},
};

void User_Task(Signal_InfoStruct *Signal)
{
	int i;
	if (!Signal)
	{
		Task_Wait(SELF_TASK_ID, SIGNAL_ANY, 0);
		return ;
	}
	for(i = 0; i < sizeof(SignalAnalyze)/sizeof(Signal_AnalyzeStruct);i++)
	{
		if (Signal->Signal == SignalAnalyze[i].Signal)
		{
			SignalAnalyze[i].Fun(Signal);
			return ;
		}
	}
	Task_Wait(SELF_TASK_ID, SIGNAL_ANY, 0);
}

void User_TaskInit(void)
{
	Task_Register(SELF_TASK_ID, User_Task, SignalBuf, TASK_SIGNAL_NUM);
	UserCtrl.RxBuf.Data = UserCtrl.RxData;
	UserCtrl.RxBuf.Pos = 0;
	UserCtrl.RxBuf.MaxLen = sizeof(UserCtrl.RxData) - 1;

	Timer_Register(&UserCtrl.RxTimer, User_UartRxTimeoutCB, NULL);
	Timer_Register(&UserCtrl.UserTimer, User_TimeoutCB, NULL);
	Uart_SetCallback(DBG_UART_ID, User_UartCB);
	Task_Wait(SELF_TASK_ID, SIGNAL_ANY, 0);
	Uart_EnableRx(DBG_UART_ID);
//	NST1001_Init();
//	Timer_Start(&UserCtrl.UserTimer, 0, 10000, 1);
}


